import exp from "constants";
import { isPromise } from "util/types";

/**
 * 规则引擎
 * @desc 问: 解决什么问题？
 * @desc 答: 代码中存在大量繁杂的if else逻辑条件, 依赖于一个或多个数据的一个或多个属性值, 决定后继逻辑的执行, 一来产生了很多魔数, 而来每次修改都会产生不可预估的逻辑大调整
 * @desc 问: 怎么解决？
 * @desc 答: 1. 确定和填写规则配置表; 2. 规则引擎加载和解析配置, 缓存到内存中, 充当逻辑代码; 3. 代码中涉及到条件判断的逻辑, 统一使用规则引擎, 索引对应模块的规则配置表, 读表返回并执行后续代码
 */
export namespace RulesEngine {
    /**
     * 数据代理接口
     */
    export interface IProxy {
        /**数据代理名 */
        name: string;
        /**数据 */
        data: any;
    }

    /**
     * 规则接口
     */
    export interface IRule {
        /**规则名 */
        name?: string;

        /**规则描述 */
        description?: string;

        /**规则优先级 */
        priority?: number;

        /**
         * 规则条件的评估
         */
        evaluate(fact: Fact<any>): boolean;

        /**
         * 规则动作的执行
         */
        execute(fact: Fact<any>): void;
    }

    /**
     * 规则
     */
    export class Rules {
        _rules: Set<IRule> = new Set();
    }

    /**
     * 事实Fact
     */
    export class Fact<T> {
        private _name: string;
        private _value: T;

        /**
         * Fact的构造函数
         * @param name
         * @param value
         */
        constructor(name: string, value: T) {
            this._name = name;
            this._value = value;
        }

        /**
         * 获取Fact名
         */
        get name(): string {
            return this._name;
        }

        /**
         * 获取Fact值
         */
        get value(): T {
            return this._value;
        }

        /**
         * @override
         */
        toString(): void {}
    }

    /**
     * 规则引擎
     */
    export class Engine {
        /**
         * 加载规则
         */
        loadRulesCfg() {}

        /**
         * 释放规则
         */
        releaseRulesCfg() {}

        /**
         * 启动规则事实
         */
        fire(rules: Rules, facts: Fact<any>) {}
    }

    /**
     * 代理映射表
     */
    export const ProxyMap: Map<string, any> = new Map();

    /**
     * 规则映射表
     */
    export const RuleMap: Map<string, new () => IRule> = new Map();

    /**
     * 注册数据代理集
     * @param proxyName
     * @returns
     */
    export function RegProxy(proxyName: string) {
        return (constructor: Function) => {
            if (ProxyMap.has(proxyName)) {
                console.error(`RegProxy : ${proxyName} is repeated !`);
            }
            ProxyMap.set(proxyName, constructor);
        };
    }

    /**
     * 注册规则集
     * @param ruleName
     * @returns
     */
    export function RegRule(ruleName: string) {
        return (constructor: new () => IRule) => {
            if (RuleMap.has(ruleName)) {
                console.error(`RegRule : ${ruleName} is repeated !`);
            }
            RuleMap.set(ruleName, constructor);
        };
    }

    /**
     * 检查规则
     * @param ruleName
     * @param proxyName
     */
    export function CheckRule(ruleName: string, proxyName: string) {
        console.assert(ProxyMap.has(proxyName), `The proxy ${proxyName} is not regist`);

        return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
            console.log(target, "-", propertyKey, "-", descriptor);
            let value = descriptor.value;
            descriptor.value = () => {
                const rule = RuleMap.get(ruleName);
                const proxy = ProxyMap.get(proxyName)!;
                const fact = new Fact(proxyName, proxy.prototype.data);
                if (rule != null && rule.prototype.evaluate(fact)) {
                    return value.call();
                } else {
                    console.log("未满足规则条件, 无法执行！");
                }
            };
        };
    }
}

// (window as any).RulesEngine = RulesEngine || {}; //web
(process as any).RulesEngine = RulesEngine || {}; //Nodejs
